﻿using System;
using System.Diagnostics.Contracts;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.IO;
using System.Net;

namespace Arachnophile
{
    /// <summary>
    /// Network & Web extensions.
    /// </summary>
    public static class NetEx
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public static string RawPathName(this Uri address)
        {
            Contract.Requires(address != null);
            Contract.Ensures(Contract.Result<string>() != null);

            return address.LocalPath.Replace('/', Path.DirectorySeparatorChar);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public static string PathName(this Uri address)
        {
            Contract.Requires(address != null);
            Contract.Ensures(Contract.Result<string>() != null);

            return address.RawPathName().Remove(Path.GetInvalidPathChars());
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public static string FileName(this Uri address)
        {
            Contract.Requires(address != null);
            Contract.Ensures(Contract.Result<string>() != null);

            return Path.GetFileName(address.PathName());
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public static FileInfo FileInfo(this Uri address)
        {
            Contract.Requires(address != null);
            Contract.Ensures(Contract.Result<string>() != null);

            return address.PathName().FileInfo();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static FileInfo FileInfo(this string path)
        {
            Contract.Requires(path != null);
            Contract.Ensures(Contract.Result<FileInfo>() != null);

            return new FileInfo(path);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public static byte[] HttpGet(this string address)
        {
            Contract.Requires(address != null);

            return new Uri(address).HttpGet();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="address"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public static byte[] HttpGet(this Uri address, int timeout = Timeout.Infinite)
        {
            Contract.Requires(address != null);

            var request = WebRequest.Create(address);
            request.Timeout = timeout;
            using (var response = request.GetResponse())
            {
                using (var stream = response.GetResponseStream())
                {
                    return stream.Data();
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static IEnumerable<byte[]> HttpGet(this IEnumerable<string> source)
        {
            Contract.Requires(source != null);
            Contract.Ensures(Contract.Result<IEnumerable<byte[]>>() != null);

            return source.Select(HttpGet);
        }
    }
}
